﻿namespace Jhong.OWINSession.Test
{
    using Jhong.OWINSession.InProcess;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System;
    using System.Threading;

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void 环形测试()
        {
            var c = new CircularCollection<string, string>();
            Assert.AreEqual(c.Test().Item1, 0);
            Assert.AreEqual(c.Test().Item2, 0);
            /*扩容测试*/
            c.Add(GR(), GR());
            Assert.AreEqual(c.Test().Item1, 1);
            Assert.AreEqual(c.Test().Item2, 1);
            c.Add(GR(), GR());
            Assert.AreEqual(c.Test().Item1, 2);
            Assert.AreEqual(c.Test().Item2, 2);
            c.Clear();
            Assert.AreEqual(c.Test().Item1, 0);
            Assert.AreEqual(c.Test().Item2, 0);
            Assert.AreEqual(c.Test().Item3, 3);
            c.Add(GR(), GR());
            c.Add(GR(), GR());
            Assert.AreEqual(c.Test().Item1, 2);
            Assert.AreEqual(c.Test().Item2, 2);
            Assert.AreEqual(c.Test().Item3, 3);
            c.Add(GR(), GR());
            Assert.AreEqual(c.Test().Item3, 3 * 2);
            Assert.AreEqual(c.Test().Item1, 3);
            Assert.AreEqual(c.Test().Item2, 3);
            c.Add(GR(), GR());
            /*删除测试*/
            var delgd = GR();
            c.Add(delgd, delgd);
            c.Add(GR(), GR());
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item1, 3 * 2);
            Assert.AreEqual(c.Test().Item2, 3 * 2);
            Assert.IsNotNull(c[delgd]);
            c.Remove(delgd);
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item1, 3 * 2);
            Assert.AreEqual(c.Test().Item2, 3 * 2);
            Assert.IsNull(c[delgd]);
            /*环形测试*/
            c.Clear();
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item1, 0);
            Assert.AreEqual(c.Test().Item2, 0);
            for (int i = 0; i < 5; i++)
            {
                c.Add(i.ToString(), i.ToString());
            }
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item1, 5);
            Assert.AreEqual(c.Test().Item2, 5);
            c.Recover((a, b) => false);
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item1, 5);
            Assert.AreEqual(c.Test().Item2, 10);
            c.Recover((a, b) => false);
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item1, 5);
            Assert.AreEqual(c.Test().Item2, 3);
            c.Recover((a, b) =>
            {
                if (Convert.ToInt32(b) >= 3) return false;
                return true;
            });
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 5);
            Assert.AreEqual(c.Test().Item1, 2);
            c.Recover((a, b) => false);
            c.Recover((a, b) => false);
            c.Recover((a, b) => false);
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 11);
            Assert.AreEqual(c.Test().Item1, 2);
            var gr1 = GR();
            c.Add(gr1, gr1);
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 0);
            Assert.AreEqual(c.Test().Item1, 3);
            var gr2 = GR();
            c.Add(gr2, gr2);
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 1);
            Assert.AreEqual(c.Test().Item1, 4);
            /*收缩测试*/
            c.Contraction();
            c.Contraction();
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 1);
            Assert.AreEqual(c.Test().Item1, 4);
            c.Contraction();
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 1);
            Assert.AreEqual(c.Test().Item1, 4);
            c.Remove(gr1);
            c.Remove(gr2);
            c.Contraction();
            c.Contraction();
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 1);
            Assert.AreEqual(c.Test().Item1, 4);
            for (int i = 0; i < 20; i++)
            {
                c.Add(i.ToString() + "a", "a");
                var x = c.Remove(i.ToString() + "a");
            }
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2 * 2);
            c.Recover((a, b) => false);
            c.Contraction();
            c.Contraction();
            c.Contraction();
            Assert.AreEqual(c.Test().Item3, 3 * 2 * 2);
            Assert.AreEqual(c.Test().Item2, 2);
            Assert.AreEqual(c.Test().Item1, 2);
            c.Clear();
            c.Recover((a, b) => false);
            c.Contraction();
            c.Contraction();
            c.Contraction();
            Assert.AreEqual(c.Test().Item3, 3 * 2);
            Assert.AreEqual(c.Test().Item2, 0);
            Assert.AreEqual(c.Test().Item1, 0);
            c.Contraction();
            c.Contraction();
            c.Contraction();
            Assert.AreEqual(c.Test().Item3, 3);
            Assert.AreEqual(c.Test().Item2, 0);
            Assert.AreEqual(c.Test().Item1, 0);
            for (int i = 0; i < 50; i++)
                c.Contraction();
            Assert.AreEqual(c.Test().Item3, 3);
            Assert.AreEqual(c.Test().Item2, 0);
            Assert.AreEqual(c.Test().Item1, 0);
        }

        [TestMethod]
        public void 随机测试()
        {
            var count = 0;
            var offset = 0;
            var size = 0;
            var random = 0;
            var real = 0;

            var x = new Random().Next(500);
            var c = new CircularCollection<string, string>();
            for (int i = 0; i < x; i++)
            {
                Assert.AreEqual(c.Test().Item1, count);
                Assert.AreEqual(c.Test().Item2, offset);
                Assert.AreEqual(c.Test().Item3, size);
                for (int j = 0; j < x; j++)
                {
                    c.Add(random.ToString(), random.ToString());
                    random++;
                    count++;
                    real++;
                    if (count >= size)
                    {
                        size = GetNextSize(size);
                        count = real;
                        offset = real;
                    }
                    else
                    {
                        offset = offset + 1 > size ? 1 : offset + 1;
                    }
                }
                Assert.AreEqual(c.Test().Item1, count);
                Assert.AreEqual(c.Test().Item2, offset);
                Assert.AreEqual(c.Test().Item3, size);
                c.Clear();
                count = 0;
                offset = 0;
                real = 0;
                Assert.AreEqual(c.Test().Item1, count);
                Assert.AreEqual(c.Test().Item2, offset);
                Assert.AreEqual(c.Test().Item3, size);
                for (int j = 0; j < x >> 1; j++)
                {
                    c.Add(random.ToString(), random.ToString());
                    random++;
                    count++;
                    offset = offset + 1 > size ? 1 : offset + 1;
                    real++;
                }
                Assert.AreEqual(c.Test().Item1, count);
                Assert.AreEqual(c.Test().Item2, offset);
                Assert.AreEqual(c.Test().Item3, size);
                for (int j = 0; j < x >> 1; j++)
                {
                    var r = random.ToString();
                    c.Add(r, r);
                    Assert.IsNotNull(c[r]);
                    c.Remove(r);
                    Assert.IsNull(c[r]);
                    random++;
                    count++;
                    offset = offset + 1 > size ? 1 : offset + 1;
                }
                Assert.AreEqual(c.Test().Item1, count);
                Assert.AreEqual(c.Test().Item2, offset);
                Assert.AreEqual(c.Test().Item3, size);
                for (int j = 0; j < x >> 1; j++)
                {
                    c.Add(random.ToString(), random.ToString());
                    random++;
                    count++;
                    real++;
                    if (count >= size)
                    {
                        size = GetNextSize(size);
                        count = real;
                        offset = real;
                    }
                    else
                    {
                        offset = offset + 1 > size ? 1 : offset + 1;
                    }
                }
                Assert.AreEqual(c.Test().Item1, count);
                Assert.AreEqual(c.Test().Item2, offset);
                Assert.AreEqual(c.Test().Item3, size);
                c.Recover((a, b) => false);
                count = real;
                offset = real + offset > size ? real + offset - size : real + offset;
                Assert.AreEqual(c.Test().Item1, count);
                Assert.AreEqual(c.Test().Item2, offset);
                Assert.AreEqual(c.Test().Item3, size);
            }
        }

        private int GetNextSize(int oldSize)
        {
            if (oldSize.Equals(0)) return 3;
            return oldSize << 1;
        }

        private string GR()
        {
            Thread.Sleep(50);
            return new Random().Next(99999).ToString();
        }
    }
}